iT邦幫忙

2023 iThome 鐵人賽

DAY 12
1

昨天我們已經實作了登入和註冊API,並了解JWT整個運作過程。
接著我們要來開發User相關的API和auth middleware開發
/images/emoticon/emoticon34.gif

大綱

  1. User API開發
  2. Auth Middleware開發
  3. 為Post API和User API加上Auth Middleware

1. User API開發

https://ithelp.ithome.com.tw/upload/images/20230927/20136558MreTArRdx7.jpg

controllers資料夾底下建立users-controller.js

//users-controller.js
const HttpError = require('../models/http-error');
const User = require('../models/User');  //記得引入User model

//取得使用者資料
exports.getUserProfile = async (req, res) => {
    try {
        const userId = req.params.userId;
        const user = await User.findById(userId);
        if (!user) {
            return next(new HttpError('查無此使用者', 404)); 
        }

        // 取得使用者資料(記得不可以回傳密碼)
        const userProfile = {
            fullName: user.fullName,
            email: user.email,
            joinDate: user.joinDate,
            bio: user.bio,
            profileImage: user.profileImage
        };

        res.json(userProfile);
        
    } catch (error) {
        next(new HttpError('Server error', 500));
    }
};

//更新使用者資料
exports.updateUserProfile = async (req, res) => {
    try {
        const userId = req.params.userId;
        const { fullName, password, bio, profileImage } = req.body;
        const updatedData = {
            ...(fullName && { fullName }),
            ...(password && { password }),
            ...(bio && { bio }),
            ...(profileImage && { profileImage })
        };

        const updatedUser = await User.findByIdAndUpdate(userId, updatedData, { new: true });

        if (!updatedUser) {
            return next(new HttpError('查無此使用者', 404)); 
        }

        const updatedProfile = {
            fullName: updatedUser.fullName,
            email: updatedUser.email,
            joinDate: updatedUser.joinDate,
            bio: updatedUser.bio,
            profileImage: updatedUser.profileImage
        };

        res.json(updatedProfile);
        
    } catch (error) {
        next(new HttpError('Server error', 500));
    }
};

接著在routes資料夾底下建立users-routes.js,並把剛剛建立user-controller.js引入

//users-routes.js

const express = require('express');
const router = express.Router();
const userControllers = require('../../controllers/users-controller');

//@router GET api/users/:userId/profile
//@desc GET 取得使用者資訊
//@access Public
router.get('/:userId/profile', userControllers.getUserProfile);

//@router PUT api/users/:userId/profile
//@desc PUT 修改使用者資料
//@access Public
router.put('/:userId/profile', userControllers.updateUserProfile);

module.exports = router;

最後在server.js引入users-routes.js

//server.js
const express = require('express');
const connectDB = require('./config/db');
const app = express();
const bodyParser = require('body-parser');
const users = require('./routes/api/users-route'); //引入users-routes.js
const auth = require('./routes/api/auth-route');
const posts = require('./routes/api/posts-route');

connectDB();

app.use(bodyParser.json());

app.use('/api/users', users);
...(略)

app.listen(PORT, () => console.log(`Server started on port ${PORT}`));

Postman測試

更新使用者資料
https://ithelp.ithome.com.tw/upload/images/20230927/201365583x6LaZwitV.jpg

取得使用者資料
https://ithelp.ithome.com.tw/upload/images/20230927/2013655852cXjsnMGE.jpg

2.Auth Middleware開發

昨天我們有介紹authorization(授權)是什麼,並且也實作了JWT(JSON Web Token)。

❓稍微再複習一下token是什麼

在前後端溝通時,token 就是前後端溝通用的憑證。前端若要和後端伺服器請求任何資料時,都必須要在發出去的請求中帶入這個 token 憑證,如果沒有攜帶憑證,或是憑證有誤的話,伺服器都不會回應請求。這個機制也是避免有未經授權的訪問和資料的竄改和偽造。


那當我們呼叫API時,該如何去驗證這個API有沒有攜帶合法憑證;若有攜帶合法憑證又該如何授權?
👉這時就要建立Auth middleware,來為我們檢驗這個API是否有攜帶或有合法的憑證

🛠️運作概念如下:
如果認證或授權失敗,Auth middleware 通常會直接回應錯誤。若認證成功,它會解析出的使用者資訊附加到請求上,然後將控制權傳遞給下一個中介軟體或路由處理程式。


建立middleware資料夾,並在底下新增auth.js檔案
https://ithelp.ithome.com.tw/upload/images/20230927/20136558nM0Uyi38BE.jpg

//auth.js

const jwt = require('jsonwebtoken');
const config = require('config');  //存取設置的私鑰

module.exports = function(req, res, next) {
    //從請求標頭中提取JWT(JSON Web Token)
    const bearerHeader =  req.header('Authorization');

    // 如果沒有則回傳錯誤
    if(!bearerHeader){
        return res.status(401).json({msg: 'No token, authorization denied'});
    }

    const bearer = bearerHeader.split(' ');
    const token = bearer[1];
    
    //檢驗憑證
    try{
        //判斷提供的憑證是否有效
        const decoded = jwt.verify(token,config.get('jwtSecret'));
        // 將解析出來的使用者資訊加到請求上
        req.user = decoded.user; 
        // 轉到下一個middleware或路由處理程式
        next(); 
    }
    catch(err){
        res.status(401).json({msg: '無效的憑證'});
    }
}

3.為Post API和User API加上Auth Middleware

完成剛剛的auth middleware後,我們就要在postuser api上加上這個中介軟體,避免未經授權的使用者去取得這些敏感資料或者進行非法的操作。

posts-routes.js

const express = require("express");
const router = express.Router();
const postControllers = require("../../controllers/posts-controller");
const auth = require("../../middleware/auth"); //引入我們剛剛的auth middleware

//@router POST /api/posts
//@desc 新增文章
//@access Public
router.post("/", auth, postControllers.createPost); //在function中間加入auth

//@router  GET api/posts/:postId
//@desc 取得單一文章
//@access Public
router.get("/:postId", auth, postControllers.getPost);

//@router PUT /api/posts/:postId
//@desc 更新文章
//@access Public
router.put("/:postId", auth, postControllers.updatePost);

//@router DELETE api/posts
//@desc 刪除文章
//@access Public*/
router.delete("/:postId",auth,postController.deletePost);

module.exports = router;

users-routes.js

const express = require('express');
const router = express.Router();
const userControllers = require('../../controllers/users-controller');
const auth = require("../../middleware/auth"); //引入我們剛剛的auth middleware

//@router GET api/users/:userId/profile
//@desc GET 取得使用者資訊
//@access Public
router.get('/:userId/profile', auth, userControllers.getUserProfile);

//@router PUT api/users/:userId/profile
//@desc PUT 修改使用者資料
//@access Public
router.put('/:userId/profile', auth, userControllers.updateUserProfile);

module.exports = router;

參考資料:


上一篇
[Day11] 登入、註冊API開發和HTTP Authentication(JWT)
下一篇
[Day13] 其他取得資料API開發
系列文
初探全端之旅: 以MERN技術建立個人部落格31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言